package org.example.springoauth2.securitycommon.config.authenticate;

import lombok.AllArgsConstructor;
import org.example.springoauth2.securitycommon.config.authenticate.grant.phone.ResourceOwnerPhoneTokenGranter;
import org.example.springoauth2.securitycommon.service.SysUserService;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;

/**
 * @author hzq
 * @date 2021/9/11 16:10
 */
@Component
@AllArgsConstructor
public class AuthorizationServerConfiguration implements AuthorizationServerConfigurer {

    private final SysUserService sysUserService;
    private final PasswordEncoder passwordEncoder;
    private final AuthenticationManager authenticationManager;
    private final TokenStore tokenStore;
    private final TokenEnhancer tokenEnhancer;
    private final DefaultTokenServices defaultTokenServices;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.allowFormAuthenticationForClients().checkTokenAccess("permitAll()");
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        /**
         * 这里基于内存配置 可以配置在数据
         * 场景：
         * 用户类型分为两种 员工/客户
         * 员工的客户端（及登录方式有三种） pc端用户名密码登录 pc端手机号码登录 微信小程序端登录
         * 客户的客户端（及登录方式有两种） 微信小程序端登录 抖音小程序登录
         */
        clients.inMemory()
                // pc端(员工) 用户名密码登录 Basic cGNfdXNlcm5hbWVfYWRtaW46cGNfdXNlcm5hbWVfYWRtaW4=
                .withClient("pc_username_admin")// 客户端id
                .secret(passwordEncoder.encode("pc_username_admin"))//客户端秘钥 需要使用加密后的
                .scopes("server")
                .authorizedGrantTypes("password", "phone", "refresh_token", "authorization_code", "client_credentials")
                .redirectUris("http://localhost/sso/login","http://localhost:9091/login")
                .autoApprove(false)
                .and()
                // pc端(员工) 电话号码登录 Basic cGNfcGhvbmVfYWRtaW46cGNfcGhvbmVfYWRtaW4=
                .withClient("pc_phone_admin")
                .secret(passwordEncoder.encode("pc_phone_admin"))
                .scopes("server")
                .authorizedGrantTypes("password", "refresh_token", "authorization_code", "client_credentials")
                .autoApprove(true)
                .and()
                // 微信小程序端(员工) 第三方code登录 Basic YXBwX3d4X2FkbWluOmFwcF93eF9hZG1pbg==
                .withClient("app_wx_admin")
                .secret(passwordEncoder.encode("app_wx_admin"))
                .scopes("server")
                .authorizedGrantTypes("refresh_token")
                .autoApprove(true)
                .and()
                // 微信小程序端(客户) 第三方code登录 Basic YXBwX3d4X2N1c3RvbWVyOmFwcF93eF9jdXN0b21lcg==
                .withClient("app_wx_customer")
                .secret(passwordEncoder.encode("app_wx_customer"))
                .scopes("server")
                .authorizedGrantTypes("refresh_token")
                .autoApprove(true)
                .and()
                // 抖音小程序端(客户) 第三方code登录 Basic YXBwX3R0X2N1c3RvbWVyOmFwcF90dF9jdXN0b21lcg==
                .withClient("app_tt_customer")
                .secret(passwordEncoder.encode("app_tt_customer"))
                .scopes("server")
                .authorizedGrantTypes("refresh_token")
                .autoApprove(true);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        // 先获取默认的
        ArrayList<TokenGranter> tokenGranters = new ArrayList<>(Arrays.asList(endpoints.getTokenGranter()));
        ResourceOwnerPhoneTokenGranter resourceOwnerPhoneTokenGranter =
                new ResourceOwnerPhoneTokenGranter(authenticationManager, defaultTokenServices,
                        endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory());
        tokenGranters.add(resourceOwnerPhoneTokenGranter);
        CompositeTokenGranter compositeTokenGranter = new CompositeTokenGranter(tokenGranters);

//        defaultTokenServices.setAuthenticationManager(authenticationManager);

        endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
                .tokenStore(tokenStore)
                .tokenEnhancer(tokenEnhancer)
                .tokenGranter(compositeTokenGranter)
                .userDetailsService(sysUserService)
                .tokenServices(defaultTokenServices)
                .authenticationManager(authenticationManager)
                .reuseRefreshTokens(false)
                .pathMapping("/oauth/confirm_access", "/token/confirm_access");
    }

}
